import { promises as fs } from "fs";
import { join, dirname } from "path";
import { glob } from "glob";
import * as path from "path";

function extractNodeId(content: string): string | null {
  // Match various patterns for node ID
  const patterns = [
    /export\s+const\s+(\w+):\s*CodeNode/,
    /id:\s*['"]([^'"]+)['"]/,
    /export\s+const\s+(\w+)\s*=\s*{[\s\S]*?id:\s*['"]([^'"]+)['"]/
  ];
  
  for (const pattern of patterns) {
    const match = content.match(pattern);
    if (match) {
      // For the third pattern, use the second capture group
      return match[2] || match[1];
    }
  }
  
  return null;
}

async function bundleFlydeSources() {
  const projectRoot = path.resolve(process.cwd());
  const outputPath = join(projectRoot, "lib/generated/node-sources.ts");

  const sources: Record<string, string> = {};

  try {
    // Find @flyde/nodes package - look for it in the monorepo
    const nodesDir = path.resolve(projectRoot, "..", "nodes");
    const nodesSrcDir = join(nodesDir, "src");

    console.log("Looking for Flyde nodes in:", nodesSrcDir);

    // Get all .flyde.ts files from @flyde/nodes/src
    const nodeFiles = glob.sync("**/*.flyde.ts", {
      cwd: nodesSrcDir,
      ignore: ["**/*.spec.ts", "**/*.test.ts"],
    });

    console.log(`Found ${nodeFiles.length} node files`);

    // Read node files
    for (const file of nodeFiles) {
      try {
        const fullPath = join(nodesSrcDir, file);
        const content = await fs.readFile(fullPath, "utf-8");
        const nodeId = extractNodeId(content);
        
        if (nodeId) {
          // Encode content as base64 to avoid escaping issues
          sources[nodeId] = Buffer.from(content).toString('base64');
          console.log(`Bundled node: ${nodeId}`);
        } else {
          console.warn(`Could not extract node ID from: ${file}`);
        }
      } catch (err) {
        console.error(`Error reading ${file}:`, err);
      }
    }

    // Also get any custom nodes from the website project
    const websiteNodeFiles = glob.sync("playground-examples/**/*.flyde.ts", {
      cwd: projectRoot,
      ignore: ["node_modules/**"],
    });

    for (const file of websiteNodeFiles) {
      try {
        const content = await fs.readFile(join(projectRoot, file), "utf-8");
        const nodeId = extractNodeId(content);
        if (nodeId) {
          sources[nodeId] = Buffer.from(content).toString('base64');
          console.log(`Bundled custom node: ${nodeId}`);
        }
      } catch (err) {
        console.error(`Error reading ${file}:`, err);
      }
    }

    console.log(`Total nodes bundled: ${Object.keys(sources).length}`);

    // Generate the output file
    const sourceContent = `// Auto-generated file. Do not edit manually.
// Generated by bundle-node-sources.ts

export const flydeSources: Record<string, string> = ${JSON.stringify(
      sources,
      Object.keys(sources).sort(),
      2
    )};

export function getNodeSource(nodeId: string): string | undefined {
  const encoded = flydeSources[nodeId];
  if (!encoded) {
    return undefined;
  }
  
  try {
    // Decode from base64 - use atob in browser, Buffer in Node.js
    if (typeof atob !== 'undefined') {
      return atob(encoded);
    } else if (typeof Buffer !== 'undefined') {
      return Buffer.from(encoded, 'base64').toString('utf-8');
    } else {
      throw new Error('No base64 decoder available');
    }
  } catch (e) {
    console.error(\`Failed to decode source for node \${nodeId}:\`, e);
    return undefined;
  }
}
`;

    // Ensure the directory exists
    await fs.mkdir(dirname(outputPath), { recursive: true });
    
    await fs.writeFile(outputPath, sourceContent);
    console.log(`Node sources bundle written to: ${outputPath}`);
  } catch (error) {
    console.error("Error bundling node sources:", error);
    process.exit(1);
  }
}

bundleFlydeSources().catch(console.error);